package gui.panels;

import application.UserLoggedManager;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.eventbus.Subscribe;
import contracts.responses.ForcedOfflineResponse;
import domain.constants.OperationType;
import domain.entities.OperationRecord;
import domain.entities.User;
import domain.services.OperationRecordDomainService;
import domain.services.UserDomainService;
import eventbus.events.UserRegisterEvent;
import gui.SubPanel;
import internal.UserLoggedInfo;
import network.websocket.WSServerSender;
import util.DialogHelper;
import util.DifferentiationHelper;
import util.JsonHelper;
import util.StringValidator;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.util.HashMap;
import java.util.Vector;

public class UserManagerSubPanel extends SubPanel {
    JTable table = new JTable();
    JScrollPane scrollPane = new JScrollPane(table);
    DefaultTableModel model = new DefaultTableModel();
    JButton queryButton = new JButton("查询全部");
    HashMap<String, User> users = new HashMap<>();
    //form items start
    JLabel idLabel = new JLabel("id:");
    JTextField idInput = new JTextField();

    JLabel usernameLabel = new JLabel("用户名:");
    JTextField usernameInput = new JTextField();

    JLabel nicknameLabel = new JLabel("昵称:");
    JTextField nicknameInput = new JTextField();

    JLabel passwordLabel = new JLabel("密码(MD5):");
    JTextField passwordInput = new JTextField();

    JLabel newPasswordLabel = new JLabel("新密码(明文):");
    JTextField newPasswordInput = new JTextField();

    JLabel createTimeLabel = new JLabel("注册时间:");
    JTextField createTimeInput = new JTextField();
    //form items end


    JButton deleteButton = new JButton("删除用户");
    JButton editButton = new JButton("保存修改");

    {
        Vector<String> vName = new Vector<>();
        vName.add("id");
        vName.add("用户名");
        vName.add("昵称");
        vName.add("密码(MD5)");
        vName.add("注册时间");
        model.setColumnIdentifiers(vName);
    }

    public UserManagerSubPanel() {
        queryButton.setBounds(100, 60, 100, 30);
        scrollPane.setBounds(100, 120, 800, 300);

        //form items setting
        idLabel.setBounds(50, 448, 50, 30);
        idInput.setBounds(100, 450, 200, 30);
        idInput.setEditable(false);
        idInput.setBackground(Color.LIGHT_GRAY);

        usernameLabel.setBounds(320, 448, 50, 30);
        usernameInput.setBounds(390, 450, 200, 30);

        nicknameLabel.setBounds(610, 448, 50, 30);
        nicknameInput.setBounds(680, 450, 200, 30);

        passwordLabel.setBounds(20, 498, 80, 30);
        passwordInput.setBounds(100, 500, 200, 30);
        passwordInput.setEditable(false);
        passwordInput.setBackground(Color.LIGHT_GRAY);

        newPasswordLabel.setBounds(305, 498, 90, 30);
        newPasswordInput.setBounds(390, 500, 200, 30);

        createTimeLabel.setBounds(610, 498, 60, 30);
        createTimeInput.setBounds(680, 500, 200, 30);
        createTimeInput.setEditable(false);
        createTimeInput.setBackground(Color.LIGHT_GRAY);

        deleteButton.setBounds(700, 550, 100, 30);
        editButton.setBounds(850, 550, 100, 30);
        this.add(scrollPane);
        this.add(queryButton);
        this.add(idLabel);
        this.add(idInput);
        this.add(usernameLabel);
        this.add(usernameInput);
        this.add(nicknameLabel);
        this.add(nicknameInput);
        this.add(passwordLabel);
        this.add(passwordInput);
        this.add(newPasswordLabel);
        this.add(newPasswordInput);
        this.add(createTimeLabel);
        this.add(createTimeInput);
        this.add(deleteButton);
        this.add(editButton);


        loadUsers();
        queryButton.addActionListener(e -> {
            loadUsers();
        });

        deleteButton.addActionListener(e -> {
            int selectedRow = table.getSelectedRow();
            User u = getSelectedUser();
            if (u == null) {
                DialogHelper.showWaringDialog("请选择一个用户");
                return;
            }
            if (DialogHelper.showConfirmDialog("删除用户", "您要删除用户[" + u.getUsername() + "]吗？")) {
                if (UserDomainService.Instance.deleteUserById(u.getId())) {
                    users.remove(u.getId());
                    model.removeRow(selectedRow);
                    try {
                        //如果用户在线(userLoggedInfo不为空)则发送让用户下线的消息
                        UserLoggedInfo userLoggedInfo = UserLoggedManager.getUserLoggedInfoByUserId(u.getId());
                        if (userLoggedInfo != null) {
                            WSServerSender.send(userLoggedInfo.getConnId(), new ForcedOfflineResponse("您的用户已经被管理员删除!"));
                        }
                        if (!OperationRecordDomainService.Instance.add(new OperationRecord(OperationType.REMOVE_USER, JsonHelper.toJson(u)))) {
                            DialogHelper.showFailDialog("删除用户成功,但记录失败!");
                            return;
                        }
                    } catch (JsonProcessingException jsonProcessingException) {
                        DialogHelper.showSuccessDialog("删除用户过程出现异常");
                        return;
                    }
                    DialogHelper.showSuccessDialog("删除用户成功");
                }
            }
        });


        editButton.addActionListener(e -> {
            User u = getSelectedUser();
            if (u == null) {
                DialogHelper.showWaringDialog("请选择一个用户");
                return;
            }
            if (DialogHelper.showConfirmDialog("修改用户", "您要保存用户的修改吗？")) {
                try {
                    //拷贝一份对象用于做修改用户明细
                    User cloneUser = u.clone();
                    if (setUser(cloneUser)) {
                        if (UserDomainService.Instance.updateUser(cloneUser)) {
                            //修改成功重新加载表格
                            loadUsers();
                            //如果用户在线(userLoggedInfo不为空)则发送让用户下线的消息
                            UserLoggedInfo userLoggedInfo = UserLoggedManager.getUserLoggedInfoByUserId(u.getId());
                            if (userLoggedInfo != null) {
                                WSServerSender.send(userLoggedInfo.getConnId(), new ForcedOfflineResponse("用户信息修改,身份信息失效"));
                            }
                            //记录修改明细
                            String diff = DifferentiationHelper.diff(u, cloneUser);
                            if (!OperationRecordDomainService.Instance.add(new OperationRecord(OperationType.UPDATE_USER, diff))) {
                                DialogHelper.showWaringDialog("修改用户信息成功,但记录修改明细失败");
                                return;
                            }
                            DialogHelper.showSuccessDialog("保存用户修改成功");
                            return;
                        }
                        DialogHelper.showFailDialog("保存用户修改失败!");
                    }
                } catch (Exception exception) {
                    DialogHelper.showFailDialog("修改过程出现异常!");
                }
            }

        });
        table.getSelectionModel().addListSelectionListener(e -> selectedTableRowUserInfo());

    }


    void loadUsers() {
        clearTable();
        UserDomainService.Instance.getAllUser().forEach(u -> {
            users.put(u.getId(), u);
        });
        users.values().forEach(this::addUserInfoToTable);
    }

    void clearTable() {
        while (model.getRowCount() > 0) {
            model.removeRow(model.getRowCount() - 1);
        }
    }


    User getSelectedUser() {
        int selectedRow = table.getSelectedRow();
        if (selectedRow != -1) {
            String id = table.getValueAt(selectedRow, 0).toString();
            return users.get(id);
        }
        return null;
    }

    boolean setUser(User u) {
        int selectedRow = table.getSelectedRow();
        String id = table.getValueAt(selectedRow, 0).toString();
        String oldUsername = table.getValueAt(selectedRow, 1).toString();
        String idInputText = idInput.getText();
        String username = usernameInput.getText();
        String nickname = nicknameInput.getText();
        String newPassword = newPasswordInput.getText();
        if (!id.equals(idInputText)) {
            DialogHelper.showFailDialog("系统出现错误!");
            return false;
        }
        //diff
        if (StringValidator.isBlank(username)) {
            DialogHelper.showWaringDialog("用户名不允许为空");
            return false;
        }
        if (StringValidator.isBlank(nickname)) {
            DialogHelper.showWaringDialog("昵称不允许为空");
            return false;
        }
        if (!oldUsername.equals(username) && UserDomainService.Instance.checkUsernameRegister(username)) {
            DialogHelper.showWaringDialog("用户名已经被注册,换一个试试吧");
            return false;
        }
        try {
            if (!StringValidator.isBlank(newPassword)) {
                u.setPassword(newPassword);
            }
        } catch (Exception exception) {
            DialogHelper.showFailDialog("md5加密出现错误!");
            return false;
        }
        u.setNickname(nickname);
        u.setUsername(username);
        return true;
    }


    //展示选择用户的信息
    void selectedTableRowUserInfo() {
        int selectedRow = table.getSelectedRow();
        clearFormItemValues();
        if (selectedRow != -1) {
            String id = table.getValueAt(selectedRow, 0).toString();
            String username = table.getValueAt(selectedRow, 1).toString();
            String nickname = table.getValueAt(selectedRow, 2).toString();
            String password = table.getValueAt(selectedRow, 3).toString();
            String createTime = table.getValueAt(selectedRow, 4).toString();
            idInput.setText(id);
            usernameInput.setText(username);
            nicknameInput.setText(nickname);
            passwordInput.setText(password);
            createTimeInput.setText(createTime);
        }
    }

    //清楚底部展示栏信息
    void clearFormItemValues() {
        newPasswordInput.setText("");
        idInput.setText("");
        usernameInput.setText("");
        nicknameInput.setText("");
        passwordInput.setText("");
        createTimeInput.setText("");
    }


    void addUserInfoToTable(User u) {
        Object[] obj = new Object[]{u.getId(), u.getUsername(), u.getNickname(), u.getPassword(), u.getCreateTime()};
        model.addRow(obj);
        table.setModel(model);
    }

    @Subscribe
    public void userRegister(UserRegisterEvent e) {
        loadUsers();
    }

}
